package top.wineye.spring.bean.definition;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import top.wineye.model.User;

import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;

@Import({AnnotationBeanDefinitionDemo.Config.class})
public class AnnotationBeanDefinitionDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext();

        /*
            register 方法来自 AnnotationConfigRegistry
            实现上 register 方法调用了来自 AnnotatedBeanDefinitionReader#registry 方法

         */

        context.register(AnnotationBeanDefinitionDemo.class);

        context.refresh();

        // 1. 通过 @Bean 方式
        // User user = context.getBean(User.class);
        System.out.println("beans of User.class type: "
                + context.getBeansOfType(User.class));

        // 2. 通过 @Component 注解的方式
        // 3. 通过 @Import 的方式
        System.out.println("beans of Config.class type: " +
                context.getBeansOfType(Config.class));


        /*
            实际上 AnnotationConfigApplicationContext 是实现了 BeanDefinitionRegistry 接口的
            因此 AnnotationConfigApplicationContext 就是一个 BeanDefinitionRegistry
            准确的说 GenericApplicationContext 实现了 BeanDefinitionRegistry，
            因此所有的 GenericApplicationContext 子类都是 BeanDefinitionRegistry
         */
        // 指定名称
        registerUserBeanDefinition(context, "user-jeff");
        // 不指定名称 generatedName
        registerUserBeanDefinition(context);

        User userJeff = (User) context.getBean("user-jeff");
        System.out.println("registered user :" + userJeff);

        System.out.println("beans of User.class type: "
                + context.getBeansOfType(User.class));

        context.close();
    }


    private static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
        BeanDefinitionBuilder bdBuilder = genericBeanDefinition(User.class);
        bdBuilder
                .addPropertyValue("id", 2)
                .addPropertyValue("name", "jeff");
        if (StringUtils.hasText(beanName)) {
            registry.registerBeanDefinition(beanName, bdBuilder.getBeanDefinition());
        } else {
            BeanDefinitionReaderUtils.registerWithGeneratedName(bdBuilder.getBeanDefinition(), registry);
        }

    }

    private static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
        registerUserBeanDefinition(registry, null);
    }

    /*
        对于没有指定 name 的 Bean Definition
        bean 的 name 根据 BeanNameGenerator#generateBeanName  生成
        对于 AnnotationConfigApplicationContext
        对应的 BeanNameGenerator 是 AnnotationBeanNameGenerator
     */

    @Component
    public static class Config {

        @Bean(name = {"user", "user-wineye"})
        public User user() {
            User u = new User();
            u.setId(1);
            u.setName("wineye");
            return u;
        }

    }
}
